/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */

#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include "mysql.h"
#include <string.h>

int error = 0;

#define PROMPT "command>"
#define BUFF_SIZE	0xff
#define SELECT 0
#define UPDATE 1
#define INSERT 2
#define DELETE 3
#define DESC 4
#define LIST 251
#define HELP 252
#define QUIT 253
#define OTHER 254
#define UNKNOWN 255

typedef struct _context
{
  char host[31];
  unsigned port;
  char user[15];
  char pwd[31];
  char db[31];
} context;

void my_help()
{
  printf("usage: db2cli -uroot -p123 -h127.0.0.1 -P13306\n"
         "-h connect addr.\n"
         "-p connect tcp port.\n"
         "-u username.\n"
         "-p password.\n"
         "-d database.\n");
  return;
}

void cmdhelp()
{
  printf("quit: quit command line.\n"
         "help: print information for help.\n"
         "list: list history command.\n"
         "connect: user@ip:port-db/password."
         "change connection to new db.\n"
         );

  return;
}

void welcome()
{
  printf("Welcome to db2cli, shell@Copyleft.\n"
         "Author, tangchao@360buy.com.\n"
         "-----------------------------------------\n");
  return;
}

void cmdline_parse(int argc, char *argv[], context *config)
{
  /* Input Check */
  if (argc == 1)
  {
    sprintf(config->host, "%s", "localhost");
    sprintf(config->user, "%s", "root");
    sprintf(config->pwd, "%s", "123456");
    sprintf(config->db, "%s", "test");
    return;
  }

  /* Parse command line */
  int opt;
  while ( 1 )
  {
    opt = getopt(argc, argv, "u:p:d:h:P:");
    if (opt == EOF) break;
    switch (opt) {
    case 'h':
      memset(config->host, 0, 32);
      memcpy(config->host, optarg, 32);
      break;
    case 'P':
      config->port = atoi(optarg);
      break;
    case 'u':
      memset(config->user, 0, 16);
      memcpy(config->user, optarg, 16);
      break;
    case 'p':
      memset(config->pwd, 0, 32);
      memcpy(config->pwd, optarg, 32);
      break;
    case 'd':
      memset(config->db, 0, 32);
      memcpy(config->db, optarg, 32);
      break;
    case '?':
      printf("Unknown options\n");
      my_help();
      exit(1);
    case ':':
      printf("Format error\n");
      my_help();
      exit(1);
    default:
      printf("International error.\n");
    }
  }
  return;
}

MYSQL* create_connect(context *config, MYSQL *mysql)
{
  mysql = mysql_init(mysql);
  if (!mysql_real_connect(mysql, config->host, config->user,
                          config->pwd, config->db, config->port, NULL, 0))
  {
    printf("Eror connecting to database: %s,error code:%d\n",
           mysql_error(mysql), mysql_errno(mysql));
    if (mysql->free_me)
    {
      mysql_close(mysql);
    }
    return NULL;
  }
  mysql->reconnect = 1;
  return mysql;
}

void strtrim_eof(char *str)
{
  int len = strlen(str);
  if (str[len - 1] == '\n')
  {
    str[len - 1] = '\0';
  }
  return;
}

char *strtrim_begin(char *str)
{
  char *it = NULL;
  while (*str == ' ' && *str)
  {
    ++str;
  }
  it=str;
  while (*str)
  {
    str++;
  }
  while (*(--str) == ' ');
  *(++str)='\0';
  return it;
}

char *strtrim(char *s)
{
  strtrim_eof(s);
  return strtrim_begin(s);
}

int cmd_parse(char *s)
{
  char cmd_flag[5];
  int i = 0;

  if (strcmp(s, "quit") == 0)
  {
    return QUIT;
  }
  if (strcmp(s, "help") == 0)
  {
    return HELP;
  }
  if (strcmp(s, "list") == 0)
  {
    return LIST;
  }
  if (strlen(s) > 4 && s[0] == 'd' && s[1] == 'e'
      && s[2] == 's' && s[3] == 'c')
  {
    return DESC;
  }
  for (; i < 6; i++)
  {
    cmd_flag[i] = s[i];
  }
  if (strlen(s) > 6 && strcmp(cmd_flag, "select") == 0)
  {
    return SELECT;
  }
  if (strlen(s) > 6 && strcmp(cmd_flag, "update") == 0)
  {
    return UPDATE;
  }
  if (strlen(s) > 6 && strcmp(cmd_flag, "insert") == 0)
  {
    return INSERT;
  }
  if (strlen(s) > 6 && strcmp(cmd_flag, "delete") == 0)
  {
    return DELETE;
  }
  if (strlen(s) > 6)
  {
    return OTHER;
  }
  return UNKNOWN;
}

int main(int argc, char *argv[])
{
  MYSQL_RES *res = NULL;
  MYSQL_ROW row;
  MYSQL_FIELD *fields = NULL;
  char buff[BUFF_SIZE], *sql;
  int flag = 0, field_num = 0, row_num = 0, t = 0, sqltype = 0;
  long affected_rows = 0;
  unsigned len = 0;
  context config;
  cmdline_parse(argc, argv, &config);

  MYSQL *mysql = NULL;
  mysql = create_connect(&config, mysql);
  if (mysql == NULL)
  {
    printf("Create connections failed.\n");
    return 1;
  }

  welcome();
  while (1)
  {
    printf("%s@%s:%u-%s %s", config.user, config.host, config.port, config.db, PROMPT);
    memset(buff, 0, BUFF_SIZE + 1);
    fgets(buff, BUFF_SIZE, stdin);
    sql = strtrim(buff);
    len = strlen(sql);
    if (len == 0)
    {
      continue;
    }
    sqltype = cmd_parse(sql);
    if (sqltype == QUIT)
    {
      goto end;
    }
    if (sqltype == HELP)
    {
      cmdhelp();
      continue;
    }
    if (sqltype == LIST)
    {
      mysql_info(mysql);
      continue;
    }
    flag = mysql_real_query(mysql, sql, (unsigned int) strlen(sql));
    if (flag)
    {
      printf("%s, %s, %d\n", sql, mysql_error(mysql), mysql_errno(mysql));
      continue;
    }
    if (sqltype == INSERT || sqltype == DELETE || sqltype == UPDATE)
    {
      affected_rows = mysql_affected_rows(mysql);
      printf("effected rows:%ld\n", affected_rows);
      continue;
    }
    if (sqltype == SELECT || sqltype == DESC || sqltype == OTHER)
    {
      res = mysql_store_result(mysql);
      if (res == '\0')
      {
        printf("Row count:0\n");
        continue;
      }
      field_num = mysql_num_fields(res);
      row_num = mysql_num_rows(res);
      fields = mysql_fetch_fields(res);
      if (fields != NULL)
      {
        for (t = 0; t < field_num; t++)
        {
          printf("%s\t", fields[t].name);
        }
        printf("\n");
      }
      while ((row = mysql_fetch_row(res)) != '\0')
      {
        for (t = 0; t < field_num; t++)
        {
          printf("%s\t", row[t]);
        }
        printf("\n");
      }
      printf("Row count:%d\n", row_num);
      mysql_free_result(res);
    }
    if (sqltype == UNKNOWN)
    {
      printf("Unknown command.\n");
    }
  }
end:
  mysql_close(mysql);
  return 0;
}
